
/****************************************************************************
**
** Copyright (C) 2004-2008 VATATA.com . All rights reserved.
**
** This file is the part of the Miniutil Poject of VATATA.com.
** Vatata's miniutil library is lightweight and portable (for linux
** and Windows). The C++ Class Library included Threadpool, Dll danymic loading, 
** General socket application model and tcp server, httpserver/servlet, etc. 
** It is a pratical utility disigned for who don't want learn the Big C++ 
** Developing Platform, such as  Boost or ACE.
**
** This file may be used under the terms of the GNU General Public
** License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the files LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file.  Alternatively you may (at
** your option) use any later version of the GNU General Public
** License if such license has been publicly approved by VATATA.com.
** (or its successors, if any) and the Miniutil Project Aministrators. 
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://www.gnu.org/licenses/lgpl.html. If you are unsure which 
** license is appropriate for your use, please review the following 
** information: http://code.google.com/p/miniutil/ or contact 
** http://www.vatata.com.
**
** In addition, as a special exception, VATATA.com, as the sole
** copyright holder for Miniutil Project, grants users of VATATA
** P2P Platform the right to release and package with the related 
** libraries without the source code.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. vatata reserves all rights not expressly
** granted herein.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/


#include "miniutil/strutil.h"
#include "miniutil/address.h"
#include "miniutil/socket.h"
#include "miniutil/log.h"

using namespace miniutil;

#ifndef WIN32
#include <signal.h>
#include <sys/types.h>       
#include <sys/param.h>       
#include <sys/ioctl.h>       
#include <sys/socket.h>
#include <netdb.h> 
#include <net/if.h>       
#include <netinet/in.h>       
#include <net/if_arp.h>       
#include <arpa/inet.h>   
#endif
#include <vector>


namespace miniutil
{
    namespace net
    {
	    class __sock_init
	    {
	    public:
		    static bool socket_initialized ;

		    __sock_init()
		    {
                this->init();
		    }

		    ~__sock_init()
		    {
#ifdef WIN32
			    WSACleanup();
#endif
			    socket_initialized = false;
		    }

            void init()
            {
			    if (socket_initialized) return ;
#ifdef WIN32
			    WSADATA wsdata;
			    if (WSAStartup(MAKEWORD(1, 1), &wsdata)) return ;
			    //if (WSAStartup(MAKEWORD(2, 0), &wsdata)) return ;
#else
                signal(SIGPIPE,SIG_IGN);
#endif
			    socket_initialized = true;
                //L_DEBUG("Winsock initialized!\r\n");
            }
    		
	    };

	    bool __sock_init::socket_initialized = false;
	    static __sock_init __sock_init_instance;
    }
}


ip4addr ip4addr::LOCALHOST()
{
	return ip4addr(local);
}

ip4addr ip4addr::INETANY()
{
	return ip4addr( any );
}

ip4addr ip4addr::MYSELF()
{
#ifdef WIN32
    if (  !miniutil::net::__sock_init::socket_initialized  )
        miniutil::net::__sock_init_instance.init();

	char buf[256];
	if ( gethostname(buf, 255 ) == 0 )
		return ip4addr( buf );
	else
		return LOCALHOST();
#else
	std::vector<struct in_addr> rtnvec;
	int fd, intrface;       
	struct ifreq buf[16];       
	struct arpreq arp;       
	struct ifconf ifc; 

	if ((fd = ::socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
	{
		ifc.ifc_len = sizeof(buf);       
		ifc.ifc_buf = (caddr_t) buf;       
		if (!ioctl(fd, SIOCGIFCONF, (char *) &ifc))   
		{   
			intrface = ifc.ifc_len/sizeof(struct ifreq);     
			for(int i=0; i< intrface; i++)
			{   
				//printf("net device %s\n", buf[i].ifr_name);       
				/*Jugde whether the net card status is promisc     */       
				if (!(ioctl(fd, SIOCGIFFLAGS, (char *)&buf[i])))   
				{   
					if (buf[i].ifr_flags & IFF_PROMISC)   
					{   
						continue;   
					}   
				}   
				else   
				{   
					continue;
				}

				if (!(buf[i].ifr_flags & IFF_UP))
					continue;

				/*Get IP of the next card   */
				if (!(ioctl(fd, SIOCGIFADDR, (char *) &buf[i])))   
				{   
					//printf("IP address is: %s\n",inet_ntoa(((struct   sockaddr_in   *) (&buf[i].ifr_addr))->sin_addr));       
					struct in_addr addr= (((struct sockaddr_in*) (&buf[i].ifr_addr))->sin_addr);
					if(inet_addr("127.0.0.1") != addr.s_addr)
						rtnvec.push_back(addr);
				}   
			}
		}
	}

	if(rtnvec.size() > 0)
	{
		return ip4addr(inet_ntoa(rtnvec[0]));
	}
	else
		return LOCALHOST();

#endif
}


ip4addr::ip4addr( const char * hostnamein )
{
	if ( hostnamein == NULL )
	{
		addr = any;
		return;
	}

	unsigned int a,b,c,d;
	int count = sscanf( hostnamein, "%u.%u.%u.%u", &a,&b,&c,&d );
	if ( count == 4 && a < 255 && b < 255 && c<255 && d<255 )
	{
		addr = ( a<<24 | b<<16 | c<<8 | d );
        addrda = htonl(addr);
		return;
	}

	struct hostent* hostEntry;
	hostEntry = gethostbyname(hostnamein);
	  
	if (hostEntry == NULL ) 
		addr = ( any );
	else
	{
		memcpy((char*)&addr, hostEntry->h_addr_list[0], sizeof(unsigned long));
		addr = ntohl(addr);
		//addr = ntohl( *(unsigned long *)hostEntry->h_addr_list[0]);
	}
    addrda = htonl(addr);
}

ip4addr::ip4addr( string &hostnamein )
{
	unsigned int a,b,c,d;
	int count = sscanf( hostnamein.c_str(), "%u.%u.%u.%u", &a,&b,&c,&d );
	if ( count == 4 && a < 255 && b < 255 && c<255 && d<255 )
	{
		addr = ( a<<24 | b<<16 | c<<8 | d );
        addrda = htonl(addr);
		return;
	}

	struct hostent* hostEntry;
	hostEntry = gethostbyname(hostnamein.c_str() );
	  
	if (hostEntry == NULL ) 
		addr = ( any );
	else
	{
		memcpy((char*)&addr, hostEntry->h_addr_list[0], sizeof(unsigned long));
		addr = ntohl(addr);
		//addr = ntohl( *(unsigned long*)hostEntry->h_addr_list[0]);
	}
    addrda = htonl(addr);
}


ip4addr::ip4addr(const string &hostnamein )
{
	unsigned int a,b,c,d;
	int count = sscanf( hostnamein.c_str(), "%u.%u.%u.%u", &a,&b,&c,&d );
	if ( count == 4 && a < 255 && b < 255 && c<255 && d<255 )
	{
		addr = ntohl( a<<24 | b<<16 | c<<8 | d );
        addrda = htonl(addr);
		return;
	}

	struct hostent* hostEntry;
	hostEntry = gethostbyname(hostnamein.c_str() );
	  
	if (hostEntry == NULL ) 
		addr = ( any );
	else
	{
		memcpy((char*)&addr, hostEntry->h_addr_list[0], sizeof(unsigned long));
		addr = ntohl(addr);
		//addr = ntohl( *(unsigned long*)hostEntry->h_addr_list[0]);
	}
    addrda = htonl(addr);
}

bool ip4addr::isReserveIp(int ip)
{
	unsigned int ipmin;
	unsigned int ipmax;
	int i;
	const char *privateip[][2] = 
	{
		{"10.0.0.1","10.255.255.255"},
		{"127.0.0.1","127.255.255.255"},
		{"169.254.0.1","169.254.255.255"},
		{"172.16.0.1", "172.31.255.255"},
		{"192.168.0.1", "192.168.255.255"},
		{"224.0.0.0", "239.255.255.255"}
	};

	if(ip == 0x00)
		return false;
	for(i=0; i < 6; i++)
	{
		ipmin = ntohl(inet_addr(privateip[i][0]));
		ipmax = ntohl(inet_addr(privateip[i][1]));
		if( (unsigned int)ip >= ipmin &&
			(unsigned int)ip <= ipmax )
			return true;
	}
	return false;
}

std::string ip4addr::IP() const
{
//	char buf[80];
//#ifdef WIN32				
//	sprintf_s(buf, 80, "%u.%u.%u.%u",(addr>>24)&0xff,(addr>>16)&0xff,(addr>>8)&0xff,addr&0xff);
//#else
//	sprintf(buf, "%u.%u.%u.%u",(addr>>24)&0xff,(addr>>16)&0xff,(addr>>8)&0xff,addr&0xff);
//#endif
//    std::string rstr;
//    rstr.assign(buf);
    std::string rstr = miniutil::strutil::format("%u.%u.%u.%u",(addr>>24)&0xff,(addr>>16)&0xff,(addr>>8)&0xff,addr&0xff);
	return rstr;
}



soaddr::soaddr(const string & soaddress_string  )
{
	std::string::size_type len = soaddress_string.find_first_of(':');
	if ( len == std::string::npos )
	{
		port = 0;
		this->ip = ip4addr( soaddress_string );
		return;
	}

	std::string ip_str = soaddress_string.substr(0, len  );
	std::string port_str = soaddress_string.substr( len + 1 );

	this->ip = ip4addr( ip_str );
	this->port = atoi( port_str.c_str() );
}




